﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

using System.IO;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Storage;

using Engine;

namespace Game
{
    [Serializable]
    public class InventoryData
    {
        public List<Pair<string,short>> mInventory;

        /*
        public Inventory CreateInventoryFromData()
        {
            Inventory inventory = new Inventory(4, new Vector2(0, 0), 1);

            for(byte e=0;e<mInventory.Count;e++)
                for(byte a=0;a<mInventory[e].Second;a++)
                    inventory.Add(ItemList.GetItem(mInventory[e].First));
            
            return inventory;
        }
        */

        public List<Pair<Item, short>> CreateInventoryFromData()
        {
            List<Pair<Item, short>> inventory = new List<Pair<Item, short>>();

            for (byte e = 0; e < mInventory.Count; e++)
                inventory.Add(new Pair<Item,short>(ItemList.GetItem(mInventory[e].First),mInventory[e].Second));

            return inventory;
        }

        public void CreateDataFromInventory(Inventory inventory)
        {
            mInventory = new List<Pair<string, short>>();

            for (byte e = 0; e < inventory.mInventory.Count; e++)
                mInventory.Add(new Pair<string, short>(inventory.mInventory[e].First.Name, inventory.mInventory[e].Second));
        }
    }

    public static class InventoryManager
    {
        public static InventoryData data = new InventoryData();
             
        public static void SaveFile(string filename, Inventory inventory)
        {
            data.CreateDataFromInventory(inventory);

            string fullpath = Path.Combine(StorageContainer.TitleLocation, filename);
            FileStream stream = File.Open(fullpath, FileMode.Create);
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(InventoryData));
                serializer.Serialize(stream, data);
            }
            finally
            {
                stream.Close();
            }
        }

        public static List<Pair<Item, short>> LoadFile(string filename)
        {
            string fullpath = Path.Combine(StorageContainer.TitleLocation, filename);
            FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate, FileAccess.Read);
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(InventoryData));
                data = (InventoryData)serializer.Deserialize(stream);

                return data.CreateInventoryFromData();
            }
            catch { }
            finally
            {
                stream.Close();
            }

            return null;
        }
    }

    public class Inventory
    {
        Texture2D   mTemplateTexture;
        SpriteFont  mFontTexture;

        public List<Pair<Item, short>> mInventory;    //Lista de ITEMS & su CANTIDAD

        short mExplorer;      //SLOT seleccionado actual
        short mDisplacement;  //CANTIDAD de SLOTS escondidos entre el primer visible y el primero
        short mShowingRange;  //CANTIDAD de SLOTS visibles

        Vector2 mPosition;              //Posicion del INVENTARIO
        Vector2 mItemActualLocation;    //Acomoda el ITEM correctamente en el INVENTARIO
        float   mScale;                 //MODIFICADOR de tamaño de la Textura de los ITEMS

        byte mAlpha;         //OPACIDAD del INVENTARIO
        bool mIsActive;      //¿Esta listo para usarse?
        bool mIsOpening;     //¿Se esta abriendo?
        bool mIsClosing;     //¿Se esta cerrado?

        short mItemDesiredSize;
        
        Rectangle Blank                 = new Rectangle(000, 368, 100, 100);

        Rectangle Left                  = new Rectangle(  0,   0,  78, 233);
        Rectangle Center                = new Rectangle( 80,   0, 150, 233);
        Rectangle Right                 = new Rectangle(232,   0,  78, 233);

        Rectangle ActiveLeftArrow       = new Rectangle(  0, 240, 135,  63);
        Rectangle ActiveRightArrow      = new Rectangle(143, 240, 135,  63);
        Rectangle UnActiveLeftArrow     = new Rectangle(  0, 304, 135,  63);
        Rectangle UnActiveRightArrow    = new Rectangle(143, 304, 135,  63);

        public Inventory(short ShowingRange, Vector2 position, float scale)
        {
            mInventory          = new List<Pair<Item, short>>();

            mExplorer           = 0;
            mDisplacement       = 0;
            mShowingRange       = ShowingRange;

            mPosition           = position;
            mScale              = 100.0f/128.0f;

            mAlpha              = 0;
            mIsActive           = false;
            mIsOpening          = false;
            mIsClosing          = false;

            mItemDesiredSize    = 100;

            mItemActualLocation = new Vector2(mItemDesiredSize / 4.0f, (Center.Height - mItemDesiredSize) / 2.0f);

            /*EXAMPLE*/
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("HandMade Granade"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("One Slice"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("Two Slices"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("Three Slices"));
            Add(ItemList.GetItem("Bomb"));
            Add(ItemList.GetItem("Holy LandMine of Antioch"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            Add(ItemList.GetItem("Adhesive Tape"));
            /*EXAMPLE*/
        }

        public void TextureLoader(Texture2D texture, SpriteFont font)
        {
           mTemplateTexture = texture;
           mFontTexture = font;
        }

        public short GetSelected() { return (short)(mDisplacement + mExplorer); }

        public List<Pair<Item, short>> GetInventory() { return mInventory; }

        public void Draw(SpriteBatch sb)
        {
            if (mIsActive)
            {
                Color color = new Color(Color.White, mAlpha);

                #region LeftArrowManagement
                Vector2 ArrowPosition = mPosition;              //La Posiciona en el Menu
                ArrowPosition.Y -= ActiveLeftArrow.Height / 2;  //Mueve el "Pivot" de la Flecha
                ArrowPosition.Y += Center.Height / 2;           //Y la ubica en el Centro del Menu

                if (mDisplacement <= 0)         //Si es el primer elemento del Menu
                    sb.Draw(mTemplateTexture,   //texture
                            ArrowPosition,          //position
                            UnActiveLeftArrow,      //rectangle
                            color,                  //color
                            0,                      //angle
                            Vector2.Zero,           //origin
                            1,                      //scale
                            SpriteEffects.None,     //???
                            0);                     //???
                else                            //Sino...
                    sb.Draw(mTemplateTexture,   //texture
                            ArrowPosition,          //position
                            ActiveLeftArrow,        //rectangle
                            color,                  //color
                            0,                      //angle
                            Vector2.Zero,           //origin
                            1,                      //scale
                            SpriteEffects.None,     //???
                            0);                     //???
                #endregion

                #region RightArrowManagement
                ArrowPosition = mPosition;                 //La Posiciona en el Menu
                ArrowPosition.Y -= ActiveRightArrow.Height / 2;    //Mueve el "Pivot" de la Flecha
                ArrowPosition.Y += Center.Height / 2;              //Y la ubica en el Centro del Menu

                ArrowPosition.X += Left.Width;                     //Mueve la Flecha al final del Template Izquierdo
                ArrowPosition.X += Center.Width * mShowingRange;   //Mueve la Flecha al final del Template Central por cada uno Q' hay
                ArrowPosition.X += Right.Width;                    //Mueve la Flecha al final del Template Derecho

                if (mDisplacement + mShowingRange < mInventory.Count)   //Si no es el ultimo elemento del Menu
                    sb.Draw(mTemplateTexture,   //texture
                            ArrowPosition,     //position
                            ActiveRightArrow,       //rectangle
                            color,                  //color
                            0,                      //angle
                            Vector2.Zero,           //origin
                            1,                      //scale
                            SpriteEffects.None,     //???
                            0);                     //???   
                else                                                    //Sino...
                    sb.Draw(mTemplateTexture,   //texture
                            ArrowPosition,     //position
                            UnActiveRightArrow,     //rectangle
                            color,                  //color
                            0,                      //angle
                            Vector2.Zero,           //origin
                            1,                      //scale
                            SpriteEffects.None,     //???
                            0);                     //???
                #endregion

                #region LeftBorderManagement
                Vector2 MenuPosition = mPosition;                 //Lo Posiciona en donde deberia empezar
                MenuPosition.X += ActiveLeftArrow.Width / 2;      //Lo Desplaza para Q' empieze con la Flecha Izquierda

                sb.Draw(mTemplateTexture, MenuPosition, Left, color);
                #endregion

                #region CenterManagement
                MenuPosition.X += Left.Width; //Lo desplaza lo Q' ocupa el Border Izquierdo
                for (short e = 0; e < mShowingRange; e++) //Para cada Item a mostrar
                {
                    sb.Draw(mTemplateTexture, MenuPosition, Center, color);

                    Vector2 ItemPosition = mPosition;                           //Lo Posiciona en donde deberia empezarel INVENTARIO.
                    ItemPosition.X += ActiveLeftArrow.Width / 2;                //Mueve la posicion lo que ocupa la FLECHA IZQ.
                    ItemPosition.X += Left.Width;                               //Mueve la posicion lo que ocupa el BORDE IZQ.
                    ItemPosition.X += mItemActualLocation.X * (e + 1);          //Mueve la posicion para imprimir el ITEM en el centro del CENTRO
                    ItemPosition.X += mItemDesiredSize * e;                     //Mueve la posicion para imprimir el ITEM por separado de los demas
                    ItemPosition.X += mItemActualLocation.X * e;                //Mueve la posicion para imprimir el ITEM en el centro del CENTRO

                    ItemPosition.Y += mItemActualLocation.Y;                    //Mueve la posicion al lugar donde el se va dibujar el ITEM.
                
                    if ((e + mDisplacement) < mInventory.Count)
                    {
                        sb.Draw(ItemList.mItemTexture,                          //texture
                                ItemPosition,                                   //position
                                mInventory[e + mDisplacement].First.Rectangle,  //rectangle
                                color,                                          //color
                                0,                                              //angle
                                Vector2.Zero,                                   //origin
                                mScale,                                         //scale
                                SpriteEffects.None,                             //???
                                0);                                             //???

                        if (mIsActive)
                        {
                            string ammount = mInventory[e + mDisplacement].Second.ToString();

                            Vector2 StringPosition = ItemPosition;
                            StringPosition.X += mItemDesiredSize;
                            StringPosition.Y += mItemDesiredSize;
                            StringPosition -= mFontTexture.MeasureString(ammount);

                            sb.DrawString(  mFontTexture,
                                            ammount,
                                            StringPosition,
                                            new Color(Color.Black, mAlpha));
                        }
                    }
                    else
                        sb.Draw(mTemplateTexture,   //texture
                                ItemPosition,       //position
                                Blank,              //rectangle
                                color,              //color
                                0,                  //angle
                                Vector2.Zero,       //origin
                                1,                  //scale
                                SpriteEffects.None, //???
                                0);                 //???

                    MenuPosition.X += Center.Width;
                }
                #endregion

                #region RightBorderManagement
                sb.Draw(mTemplateTexture, MenuPosition, Right, color);
                #endregion

                #region CursorManagement
                if (mIsActive)
                    if (mInventory.Count > 0)
                    {
                        Vector2 CursorPosition = mPosition;                             //Lo Posiciona en donde deberia empezarel INVENTARIO.
                        CursorPosition.X += ActiveLeftArrow.Width / 2;                  //Mueve la posicion lo que ocupa la FLECHA IZQ.
                        CursorPosition.X += Left.Width;                                 //Mueve la posicion lo que ocupa el BORDE IZQ.
                        CursorPosition.X += mItemActualLocation.X * (mExplorer + 1);    //Mueve la posicion para imprimir el ITEM en el centro del CENTRO
                        CursorPosition.X += mItemDesiredSize * mExplorer;               //Mueve la posicion para imprimir el ITEM por separado de los demas
                        CursorPosition.X += mItemActualLocation.X * mExplorer;          //Mueve la posicion para imprimir el ITEM en el centro del CENTRO

                        CursorPosition.Y += mItemActualLocation.Y;                      //Mueve la posicion al lugar donde el se va dibujar el ITEM.

                        sb.Draw(mTemplateTexture,           //texture
                                CursorPosition,             //position
                                Blank,                      //rectangle
                                new Color(Color.Blue, 64),  //color
                                0,                          //angle
                                Vector2.Zero,               //origin
                                1,                          //scale
                                SpriteEffects.None,         //???
                                0);                         //???
                    }
                #endregion
            }

            #region GeneralManagement
            if (mIsOpening)
            {
                if (mAlpha < 255)
                    mAlpha += 5;
                else
                {
                    mIsOpening = false;
                    mIsActive = true;
                }
            }

            if (mIsClosing)
                if (mAlpha > 0)
                    mAlpha -= 5;
                else
                    mIsClosing = false;
            #endregion
        }

        public void ExploreLeft()
        {
            if (mIsActive)
            {
                if (mExplorer > 0)
                    mExplorer--;
                else
                    if (mDisplacement > 0)
                        mDisplacement--;
            }
        }

        public void ExploreRight()
        {
            if (mIsActive)
            {
                if (mExplorer + mDisplacement + 1 < mInventory.Count)
                    if (mExplorer + 1 < mShowingRange)
                        mExplorer++;
                    else
                        mDisplacement++;
            }
        }
        public bool IsActive
        {
            get { return mIsActive; }
        }
        public void Add(Item item)
        {
            bool found = false;

            for (short e = 0; e < mInventory.Count && !found; e++)
            {
                if (mInventory[e].First.Name == item.Name)
                {
                    mInventory[e].Second++;
                    found = true;
                }
            }

            if (!found)
                mInventory.Add(new Pair<Item, short>(item, 1));
        }

        public void QuickMenu(QuickMenu qm, short slot)
        {
            if (mInventory[mExplorer + mDisplacement].First.Name != "Adhesive Tape")
                qm.Add(mInventory[mExplorer + mDisplacement], slot);
        }

        public void Activate()
        {
            if (!mIsActive)
                mIsOpening = true;
        }

        public void DeActivate()
        {
            if (mIsActive)
            {
                mIsActive = false;
                mIsClosing = true;
            }
        }

        public void UpGrade(short slot)
        {
            short UpGrader = FindSlot("Adhesive Tape");

            if (UpGrader != -1)
            {
                if (mInventory[slot].Second > 1)
                {
                    Item upgrade = ItemList.GetUpGrade(mInventory[slot].First);

                    if (upgrade != null)
                    {
                        Add(upgrade);
                        mInventory[slot].Second -= 2;

                        if (mInventory[UpGrader].Second != 1)
                            mInventory[UpGrader].Second--;
                        else
                        {
                            ReLocate(UpGrader);
                            mInventory.RemoveAt(UpGrader);
                        }

                        if (mInventory[slot].Second == 0)
                        {
                            mInventory[slot].Second++;
                            Use(slot);
                        }
                    }
                }
            }
        }

        public short FindSlot(string item)
        {
            for (short e = 0; e < mInventory.Count; e++)
                if (mInventory[e].First.Name == item)
                    return e;
            return -1;
        }

        public void ReLocate(short slot)
        {
            if (slot < mDisplacement)   //Si sacas algo dentro de la zona desplazada
                mDisplacement--;            //Retrocede la zona por el Item Q' falta
            else
            {
                if (slot > mDisplacement && slot < (mDisplacement + mShowingRange)) //Si esta en el rango visible
                {
                    if ((mDisplacement + mExplorer) == mInventory.Count - 1)
                    {
                        if (mDisplacement > 0)
                        {
                            mDisplacement--;
                        }
                        else
                        {
                            if (mExplorer == mInventory.Count - 1)
                            {
                                mExplorer--;
                            }
                        }
                    }
                }
            }
        }

        public Item Use(short slot)
        {
            if (mInventory.Count > 0)
            {
                Item aux = mInventory[slot].First;

                if (aux.Name != "Adhesive Tape")
                {
                    if (mInventory[slot].Second != 1)
                        mInventory[slot].Second--;
                    else
                    {
                        ReLocate(slot);
                        mInventory.RemoveAt(slot);
                    }
                }

                return aux;
            }

            return null;
        }
    }
}
